package com.jinmdz.fmis.api.admin.service;

import com.jinmdz.fmis.api.admin.model.dictionarydata.DictionaryCodeData;
import com.jinmdz.fmis.api.admin.model.dictionarydata.DictionaryListItem;
import com.jinmdz.fmis.api.admin.model.servicedictionary.ServiceDictionaryDataIdData;
import com.jinmdz.fmis.api.admin.model.servicedictionary.ServiceDictionaryDataLoadData;
import com.jinmdz.fmis.api.admin.model.servicedictionary.ServiceDictionaryDataPurposeItem;
import com.jinmdz.fmis.api.admin.model.servicedictionary.ServiceDictionaryDataSaveData;
import com.jinmdz.fmis.api.api.model.common.IdVersionData;
import com.jinmdz.fmis.api.base.BaseService;
import com.jinmdz.fmis.api.model.config.dictionary.OperationLogCode;
import com.jinmdz.fmis.api.model.system.UserItem;
import com.jinmdz.fmis.api.wrapper.DictionaryWrapper;
import com.jinmdz.fmis.api.wrapper.OperationWrapper;
import com.jinmdz.fmis.common.ext.ArrayListExt;
import com.jinmdz.fmis.common.ext.StringBuilderExt;
import com.jinmdz.fmis.common.util.BeanUtil;
import com.jinmdz.fmis.common.util.DataUtil;
import com.jinmdz.fmis.core.base.BaseResult;
import com.jinmdz.fmis.core.constant.EDictCode;
import com.jinmdz.fmis.core.constant.PurposeConst;
import com.jinmdz.fmis.core.exception.ActionException;
import com.jinmdz.fmis.core.util.JacksonUtil;
import com.jinmdz.fmis.dao.admin.dao.DictionaryDataDao;
import com.jinmdz.fmis.dao.admin.dao.ServiceDictionaryDao;
import com.jinmdz.fmis.dao.admin.model.dictionarydata.DictionaryDataEditItem;
import com.jinmdz.fmis.dao.admin.model.servicedictionary.ServiceDictionaryDataEditItem;
import com.jinmdz.fmis.dao.admin.model.servicedictionary.ServiceDictionaryDataListItem;
import com.jinmdz.fmis.dao.model.dictionary.DataDictionaryItem;
import com.jinmdz.fmis.mapper.entity.ServiceDictionaryItemEntity;
import com.jinmdz.fmis.mapper.mapper.ServiceDictionaryItemMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;

/**
 * 字典费用关联及计算规则设置相关接口
 *
 * @author GuanKui
 * @date 2020/3/11 13:11
 */
@Service("serviceDictionaryService")
public class ServiceDictionaryService extends BaseService {

    @Resource
    private ServiceDictionaryItemMapper serviceDictionaryItemMapper;

    @Resource
    private ServiceDictionaryDao serviceDictionaryDao;

    @Resource
    private DictionaryDataDao dictionaryDataDao;

    @Resource
    private OperationWrapper operationWrapper;

    @Resource
    private OperationLogCode operationLogCode;

    @Resource
    private DictionaryWrapper dictionaryWrapper;

    /**
     * 加载要与费用和规则绑定的字典类型信息列表
     *
     * @param
     * @return
     * @author GuanKui
     * @date 2020/3/12  9:54
     */
    public BaseResult<ArrayList<DictionaryListItem>> loadServiceDictionaryList() {
        ArrayList<DictionaryListItem> loadItems = listServiceDictionaryList();
        return successList(loadItems);
    }

    /**
     * 加载要与费用和规则绑定的字典类型信息列表
     *
     * @param
     * @return
     * @author GuanKui
     * @date 2020/3/12  9:33
     */
    private ArrayList<DictionaryListItem> listServiceDictionaryList() {
        ArrayListExt<DictionaryListItem> dictionaryList = new ArrayListExt<>();
        // 要加载的字典编码
        EDictCode[] dictCodes = new EDictCode[]{
                EDictCode.TRANSPORT_CAR_TYPE,
                EDictCode.EQUIPMENT_TYPE,
                EDictCode.HALL_TYPE,
                EDictCode.FURNACE_TYPE
        };

        // 字典集合
        for (EDictCode eDictCode : dictCodes) {
            dictionaryList.addExt(new DictionaryListItem()
                    .setDictCode(eDictCode.getCode())
                    .setDictText(eDictCode.getMessage()));
        }
        return dictionaryList;
    }

    /**
     * 根据字典编码加载字典下的数据项列表
     *
     * @param data 字典编码
     * @return
     * @author GuanKui
     * @date 2020/3/12  11:30
     */
    public BaseResult<ArrayList<ServiceDictionaryDataListItem>> loadServiceDictionaryDataListWithCode(DictionaryCodeData data) {
        ArrayList<ServiceDictionaryDataListItem> loadItems = serviceDictionaryDao.listServiceDictionaryDataListByDictCode(data.getDictCode());
        return successList(loadItems);
    }

    /**
     * 加载字典、费用、规则数据信息
     *
     * @param data 编码主键
     * @return
     * @author GuanKui
     * @date 2020/3/12  11:30
     */
    public BaseResult<ServiceDictionaryDataLoadData> loadServiceDictionaryDataWithId(ServiceDictionaryDataIdData data) {
        // 判断数据是否完整
        if (DataUtil.invalid(data.getId()) && DataUtil.invalid(data.getDataDictionaryId())) {
            return failure("规则关联主键或字典主键必须填写一个");
        }

        // 创建返回数据
        ServiceDictionaryDataLoadData loadData = new ServiceDictionaryDataLoadData();

        // 按照获取字典及关联信息
        ServiceDictionaryDataEditItem loadItem = serviceDictionaryDao.getServiceDictionaryDataEditByDictionaryId(data.getId()
                , data.getDataDictionaryId());
        if (DataUtil.isNull(loadItem) || DataUtil.invalid(loadItem.getDataDictionaryId())) {
            return failure("信息不存在");
        }

        // 获取字典信息
        DictionaryDataEditItem dictionaryItem = dictionaryDataDao.getDictionaryDataEditById(loadItem.getDataDictionaryId());
        if (dictionaryItem != null && DataUtil.valid(dictionaryItem.getDictCode())) {
            loadData.setPurpose(listServiceDictionaryDataPurposeByType(dictionaryItem.getDictCode()));
        }

        // 设置返回数据
        loadData.setServiceDictionaryItem(loadItem)
                .setCalculateRules(serviceDictionaryDao.listServiceDictionaryDataRuleForCode(getRuleInitialCodeByType(dictionaryItem.getDictCode())));

        return successData(loadData);
    }

    /**
     * 按照字典类型获取计算规则首字母
     *
     * @param dictType 字典类型
     * @return
     * @author LiCongLu
     * @date 2020-04-14 15:24
     */
    public String getRuleInitialCodeByType(String dictType) {
        String initialCode = "";
        if (DataUtil.invalid(dictType)) {
            return "";
        }
        // 得到字典值
        EDictCode eDictCode = EDictCode.getEDictCode(dictType);
        switch (eDictCode) {
            case TRANSPORT_CAR_TYPE:
                initialCode = "A";
                break;
            case EQUIPMENT_TYPE:
                initialCode = "B";
                break;
            case HALL_TYPE:
                initialCode = "C";
                break;
            case FURNACE_TYPE:
                initialCode = "D";
                break;
        }
        return initialCode;
    }

    /**
     * 按照字典类型获取用途
     *
     * @param dictType 字典类型
     * @return
     * @author LiCongLu
     * @date 2020-03-11 16:07
     */
    public ArrayList<ServiceDictionaryDataPurposeItem> listServiceDictionaryDataPurposeByType(String dictType) {
        ArrayList<ServiceDictionaryDataPurposeItem> optionItems = new ArrayList<>();
        if (DataUtil.invalid(dictType)) {
            return optionItems;
        }
        // 得到字典值
        EDictCode eDictCode = EDictCode.getEDictCode(dictType);
        switch (eDictCode) {
            case TRANSPORT_CAR_TYPE: {
                ArrayList<DataDictionaryItem> dataList = dictionaryWrapper.listDataDictionaryItem(EDictCode.TRANSPORT_CAR_USE);
                for (DataDictionaryItem dataItem : dataList) {
                    optionItems.add(new ServiceDictionaryDataPurposeItem(dataItem.getDataText(), dataItem.getDataText()));
                }
//                optionItems.add(new ServiceDictionaryDataPurposeItem(PurposeConst.YI_TI_JIE_YUN, PurposeConst.YI_TI_JIE_YUN));
//                optionItems.add(new ServiceDictionaryDataPurposeItem(PurposeConst.SONG_HUI, PurposeConst.SONG_HUI));
            }
            break;
            case EQUIPMENT_TYPE:
                optionItems.add(new ServiceDictionaryDataPurposeItem(PurposeConst.YI_TI_LENG_CANG, PurposeConst.YI_TI_LENG_CANG));
                break;
            case HALL_TYPE:
                optionItems.add(new ServiceDictionaryDataPurposeItem(PurposeConst.SHOU_LING_TING, PurposeConst.SHOU_LING_TING));
                optionItems.add(new ServiceDictionaryDataPurposeItem(PurposeConst.GAO_BIE_TING, PurposeConst.GAO_BIE_TING));
                break;
            case FURNACE_TYPE:
                optionItems.add(new ServiceDictionaryDataPurposeItem(PurposeConst.YI_TI_HUO_HUA, PurposeConst.YI_TI_HUO_HUA));
                break;
        }
        return optionItems;
    }

    /**
     * 保存字典、费用、规则数据信息
     *
     * @param userItem 当前帐号
     * @param data     保存数据
     * @return
     * @author GuanKui
     * @date 2020/3/12  15:57
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult saveServiceDictionaryData(UserItem userItem, ServiceDictionaryDataSaveData data) throws ActionException {
        Integer id = data.getId();
        // 主键不为空
        if (DataUtil.valid(id)) {
            updateServiceDictionaryData(userItem, data);
        } else {
            id = insertServiceDictionaryData(userItem, data);
        }
        return success("保存成功");
    }

    /**
     * 插入字典、费用、规则数据信息
     *
     * @param userItem 当前帐号
     * @param data     保存数据
     * @return
     * @author LiCongLu
     * @date 2020-03-28 14:15
     */
    private Integer insertServiceDictionaryData(UserItem userItem, ServiceDictionaryDataSaveData data) throws ActionException {
        // 创建实体
        ServiceDictionaryItemEntity entity = getEntity(userItem, ServiceDictionaryItemEntity.class);

        // 覆盖数据
        BeanUtil.copy2Bean(data, entity);

        // 对现有数据进行判断处理
        checkServiceDictionaryDataValue(entity);

        // 新增服务关联信息
        serviceDictionaryItemMapper.insertServiceDictionaryItem(entity);
        // 判断新增结果
        if (DataUtil.invalid(entity.getId())) {
            throw exception("保存服务关联信息失败");
        }

        // 添加操作日志信息
        saveServiceDictionaryDataLog(userItem, operationLogCode.getUpdate(), data, null, entity);
        return entity.getId();
    }

    /**
     * 验证处理信息
     *
     * @param entity 关联信息
     * @return
     * @author LiCongLu
     * @date 2020-03-28 14:20
     */
    private void checkServiceDictionaryDataValue(ServiceDictionaryItemEntity entity) throws ActionException {

        // 验证字典数据
        if (DataUtil.invalid(entity.getDataDictionaryId())) {
            throw exception("关联字典无效");
        }

        // 验证服务项目费用数据
        if (DataUtil.invalid(entity.getServiceItemId())) {
            throw exception("关联费用无效");
        }

        // 验证用途
        if (DataUtil.invalid(entity.getPurpose())) {
            throw exception("关联用途无效");
        }

        // 验证用途是否已经存在
        Integer serviceDictionaryItemId = serviceDictionaryDao.getServiceDictionaryItemIdByPurpose(entity.getId(), entity.getDataDictionaryId(), entity.getPurpose());
        if (DataUtil.valid(serviceDictionaryItemId)) {
            throw exception("已经存在相同相同的'字典项'、'用途'");
        }
    }

    /**
     * 添加修改记录: 保存字典数据基本信息（添加、修改）
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param oldValue    旧数据
     * @param entity      保存实体
     * @return
     * @author GuanKui
     * @date 2020/3/13  16:43
     */
    private void saveServiceDictionaryDataLog(UserItem userItem, Integer logTypeCode, ServiceDictionaryDataSaveData data, String oldValue,
                                              ServiceDictionaryItemEntity entity) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("保存字典数据基本信息，字典表外键[{0}]，费用外键[{1}]，用途[{2}]，规则编码[{3}]，规则类型[{3}]，规则参数[{5}]，规则描述[{6}]，操作人员[{7}]"
                , String.valueOf(data.getDataDictionaryId()), String.valueOf(data.getServiceItemId())
                , data.getPurpose(), data.getRuleCode(), data.getRuleType(), data.getRuleParams()
                , data.getRuleDescribe(), userItem.getFullName());

        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), oldValue, JacksonUtil.obj2Json(entity));
    }

    /**
     * 更新字典、费用、规则数据信息
     *
     * @param userItem 当前帐号
     * @param data     保存数据
     * @return
     * @author LiCongLu
     * @date 2020-03-28 14:25
     */
    private void updateServiceDictionaryData(UserItem userItem, ServiceDictionaryDataSaveData data) throws ActionException {
        // 验证主键和数据版本是否存在
        if (DataUtil.isNull(data.getId(), data.getVersion())) {
            throw exception("请求主键与版本号不能为空");
        }

        // 通过主键获取服务关联信息
        ServiceDictionaryItemEntity entity = serviceDictionaryItemMapper.getServiceDictionaryItemById(data.getId());
        if (DataUtil.isNull(entity) || DataUtil.isNull(entity.getId(), entity.getVersion())) {
            throw exception("主键错误,不存在此服务字典关联信息");
        }

        // 验证服务字典关联表信息版本
        if (!DataUtil.equals(entity.getVersion(), data.getVersion())) {
            throw exception(versionError("服务字典关联表信息"));
        }

        // 记录旧数据
        String oldValue = JacksonUtil.obj2Json(entity);

        // 覆盖数据
        BeanUtil.copy2Bean(data, entity);

        // 对现有数据进行判断处理
        checkServiceDictionaryDataValue(entity);

        // 更新信息
        serviceDictionaryItemMapper.updateServiceDictionaryItem(entity);

        // 添加操作日志信息
        saveServiceDictionaryDataLog(userItem, operationLogCode.getUpdate(), data, oldValue, entity);
    }

    /**
     * 删除字典、费用、规则数据关联信息
     *
     * @param userItem 当前帐号
     * @param data     主键和数据版本
     * @return
     * @author GuanKui
     * @date 2020/3/12  15:23
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult deleteServiceDictionaryDataWithId(UserItem userItem, ArrayList<IdVersionData> data) throws ActionException {
        // 判断删除主键集合是否存在
        if (DataUtil.invalid(data)) {
            throw exception("不存在要删除的车辆信息");
        }

        // 验证主键是否重复
        if (data.size() != getRepeatIdSize(data)) {
            throw exception("车辆主键存在重复");
        }

        // 记录关联信息集合
        ArrayList<ServiceDictionaryDataEditItem> loadItems = new ArrayList<>();

        for (IdVersionData idData : data) {
            ServiceDictionaryDataEditItem loadItem = serviceDictionaryDao.getServiceDictionaryDataEditById(idData.getId());
            if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
                throw exception("主键错误,不存在此服务字典关联信息");
            }

            // 验证服务字典关联表信息版本
            if (!DataUtil.equals(loadItem.getVersion(), idData.getVersion())) {
                throw exception(versionError("服务字典关联表信息"));
            }

            // 删除关联信息
            serviceDictionaryItemMapper.deletedForServiceDictionaryItem(loadItem.getId(), userItem.getId(), loadItem.getVersion());

            // 记录关联信息
            loadItems.add(loadItem);
        }

        // 添加操作日志信息
        deleteServiceDictionaryLog(userItem, operationLogCode.getDelete(), data, loadItems);

        return success("删除完成");
    }

    /**
     * 添加删除记录:删除字典、费用、规则数据关联信息
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param loadItems   删除信息实体
     * @return
     * @author GuanKui
     * @date 2020/3/13  16:15
     */
    private void deleteServiceDictionaryLog(UserItem userItem, Integer logTypeCode, ArrayList<IdVersionData> data, ArrayList<ServiceDictionaryDataEditItem> loadItems) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("删除字典、费用、规则数据关联信息，操作人员[{0}]", userItem.getFullName());
        // 添加日志
        operationWrapper.operationLog(userItem, operationLogCode.getDelete(), builder.toString(), JacksonUtil.obj2Json(data), JacksonUtil.obj2Json(loadItems), null);
    }
}
